package com.example.matrixdemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

/**
 * @ProjectName: MatrixDemo
 * @Package: com.example.matrixdemo
 * @ClassName: MatrixLayout
 * @Description: java类作用描述
 * @Author: 作者名
 * @CreateDate: 2021/8/20 10:25
 * @UpdateUser: 更新者：
 * @UpdateDate: 2021/8/20 10:25
 * @UpdateRemark: 更新说明：
 * @Version: 1.0
 */
public class MatrixLayout extends LinearLayout {
    private Matrix mMatrix;
    private Bitmap mBitmap;
    private Paint mPaint,mPaintMask,mPaintShadow;
    private int mSliceDistance;//切片距离
    private int mSliceCount = 6;//切片数量
    private LinearGradient mLinearGradient;//渐变阴影
    private float mScaleX = 1f;//X轴的缩放比例
    private float mStartX;//用于记录开始触摸时的X轴的位置
    private float mSkewYRate = 1f;//Y轴的偏移比率
    private int mShadow = 170;//阴影透明度的最大值
    private ValueAnimator mValueAnimator;
    private Canvas mCanvas;
    private boolean isMove = false;
    private boolean mIsEx = true;//是否是展开动画，否则就是折叠
    private Status mCurrentStatus = Status.EXPANSION;//当前的状态
    private OnStatusChangeListener onStatusChangeListener;//状态变化的监听

    public MatrixLayout(Context context) {
        this(context,null);
    }

    public MatrixLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MatrixLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mMatrix = new Matrix();
        mPaint  = new Paint(Paint.ANTI_ALIAS_FLAG);

        mPaintMask = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    public OnStatusChangeListener getOnStatusChangeListener() {
        return onStatusChangeListener;
    }

    public void setOnStatusChangeListener(OnStatusChangeListener onStatusChangeListener) {
        this.onStatusChangeListener = onStatusChangeListener;
    }

    /**
     * 设置横向的缩放
     * @param mScaleX
     */
    public void setScaleX(float mScaleX) {
        this.mScaleX = mScaleX;
        postInvalidate();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mStartX = event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                isMove = true;
                //计算滑动的距离
                float moveDistance = event.getX() - mStartX;
                mStartX = event.getX();
                //缩放的偏移量
                if(moveDistance > 0){
                    //向右滑动（放大）
                    mScaleX = mScaleX + Math.abs(moveDistance) / getWidth();
                }else {
                    //向左滑动（缩小）
                    mScaleX = mScaleX - Math.abs(moveDistance) / getWidth();
                }
                //限定边界值
                if(mScaleX < 0){
                    mScaleX = 0f;
                }else if(mScaleX > 1){
                    mScaleX = 1;
                }
                postInvalidate();
                break;
            case MotionEvent.ACTION_UP:
                //手指抬起自动展开或折叠
                mIsEx = mScaleX > 0.5;
                startAnim();
                break;
        }
        return true;
    }

    /**
     * 开启或关闭
     */
    public void toggle(){
        isMove = true;
        setVisibility(VISIBLE);
        mIsEx = mCurrentStatus == Status.PUTAWAY;
        startAnim();
    }
    /**
     * 开始展开或折叠的动画
     */
    private void startAnim() {
        if(mValueAnimator != null && mValueAnimator.isRunning()){
            mValueAnimator.cancel();
        }
        mValueAnimator = ValueAnimator.ofFloat(mScaleX, mIsEx ? 1f : 0);
        //根据展开还是折叠，然后根据X轴的缩放，动态的设置动画时间
        long animDuration = (long) (mIsEx ? (1 - mScaleX) * 300 : mScaleX * 300);
        mValueAnimator.setDuration(animDuration);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scaleX = (float) animation.getAnimatedValue();
                setScaleX(scaleX);
            }
        });
        mValueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                isMove = false;
                postInvalidate();
                //改变当前的状态标记
                if(mIsEx){
                    if(mCurrentStatus == Status.PUTAWAY && onStatusChangeListener != null){
                        //状态由折叠到展开的转变
                        onStatusChangeListener.onExpansion();
                    }
                    mCurrentStatus = Status.EXPANSION;
                }else {
                    if(mCurrentStatus == Status.EXPANSION && onStatusChangeListener != null){
                        //状态由展开到折叠的转变
                        onStatusChangeListener.onPutaway();
                    }
                    //收起的时候隐藏（因为实际上）
                    setVisibility(GONE);
                    mCurrentStatus = Status.PUTAWAY;
                }
                super.onAnimationEnd(animation);
            }
        });
        mValueAnimator.start();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if(isMove){
            mSliceDistance = getWidth() / mSliceCount;
            mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            super.dispatchDraw(mCanvas);
            //根据X轴的缩放比例计算阴影（完全展开的时候没有阴影，随着折叠的时候阴影增加）
            int alpha = (int) ((1 - mScaleX) * mShadow);
            mPaintMask.setColor(Color.argb(alpha,0,0,0));
            mLinearGradient = new LinearGradient(0, 0, mSliceDistance, 0, Color.argb(alpha, 0, 0, 0), Color.TRANSPARENT, Shader.TileMode.CLAMP);
            mPaintShadow.setShader(mLinearGradient);
            //根据缩放比例计算每个切片的宽度
            mSliceDistance = (int) (getWidth() / mSliceCount * mScaleX);
            //根据X轴的缩放比例进行计算Y轴的偏移率（当X轴的缩放比例是1的时候没有错切）
            float skewYRate = mSkewYRate * (1 - mScaleX);
            //缩放的Bitmap的宽度
            int scaleBitmapWidth = (int) (getWidth() * mScaleX);
            //当计算的缩放Bitmap的宽度大于1的时候才进行绘制（否则会出现错误）
            if(scaleBitmapWidth > 1){
                //每次都复原Bitmap
                Bitmap bitmap = Bitmap.createScaledBitmap(mBitmap, scaleBitmapWidth,getHeight(),true);
                for (int i = 0; i < mSliceCount; i++) {
                    //每次都重置Matrix
                    mMatrix.reset();
                    canvas.save();
                    float symbol = -1;
                    //奇数正偶数负
                    if(i % 2 == 0){
                        symbol = 1;
                    }
                    mMatrix.preTranslate(mSliceDistance * i,0);
                    //矩阵设置偏移
                    mMatrix.preSkew(0,symbol * skewYRate);
                    canvas.setMatrix(mMatrix);
                    if(i != 0){
                        //裁剪Bitmap
                        bitmap = Bitmap.createBitmap(bitmap,mSliceDistance,0,bitmap.getWidth() - mSliceDistance,bitmap.getHeight());
                    }
                    //当切片的索引为奇数时（索引从0开始），切片是向上偏移的因此需要向下偏移一点才能显示完全
                    float offsetY = symbol * skewYRate * getWidth() * mScaleX / mSliceCount;
                    canvas.clipRect(new RectF(0,0,mSliceDistance,getHeight()));
                    canvas.drawBitmap(bitmap,0,offsetY < 0 ? -offsetY : 0,mPaint);
                    canvas.drawRect(0 ,offsetY < 0 ? -offsetY : 0,mSliceDistance,bitmap.getHeight()-offsetY,symbol > 0 ? mPaintMask:mPaintShadow);
                    canvas.restore();
                }
                bitmap.recycle();
            }
        }else if(mIsEx){
            //只有是展开的情况下才绘制布局
            super.dispatchDraw(canvas);
        }
    }

    /**
     * 当前的状态
     */
    public enum Status{
        EXPANSION,//展开
        PUTAWAY //折叠
    }

    /**
     * 状态变化的监听
     */
    public interface OnStatusChangeListener{
        /**
         * 展开
         */
        void onExpansion();

        /**
         * 折叠
         */
        void onPutaway();
    }
}
